using System;
using System.Runtime.InteropServices;

namespace HEFramework
{
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct IDStruct
    {
        public uint time; // 30bit
        public uint value; // 20bit

        public long ToLong()
        {
            ulong result = 0;
            result |= this.time;
            result <<= 30;
            result |= this.value;
            return (long)result;
        }

        public IDStruct(uint _time, uint _value)
        {
            this.time = _time;
            this.value = _value;
        }

        public IDStruct(long _id)
        {
            ulong result = (ulong)_id;
            this.value = (ushort)(result & IDGenerater.MASK_20_BIT);
            result >>= 20;
            this.time = (uint)result & IDGenerater.MASK_30_BIT;
        }

        public override string ToString()
        {
            return $"time: {this.time}, value: {this.value}";
        }
    }

    /// <summary>
    ///
    /// ID生成器
    /// 
    /// ----------------------------------------
    /// 作者 hep
    /// 创建时间：2023-11-29 14:47:58
    /// ----------------------------------------
    /// </summary>
    public class IDGenerater : Singleton<IDGenerater>, ISingletonAwake
    {
        public const int MAX_ZONE = 1024;

        public const int MASK_30_BIT = 0x3fffffff;
        public const int MASK_20_BIT = 0xfffff;

        private long epoch2023;

        private int value;
        private int instanceIdValue;

        public void Awake()
        {
            long epoch1970tick = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks / 10000;
            this.epoch2023 = new DateTime(2023, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks / 10000 - epoch1970tick;
        }

        private uint TimeSince2023()
        {
            uint a = (uint)((TimeRunner.Instance.FrameTime - this.epoch2023) / 1000);
            return a;
        }

        /// <summary>
        /// 生成实例ID
        /// </summary>
        /// <returns></returns>
        public long GenerateInstanceID()
        {
            uint time = TimeSince2023();
            int v = 0;
            // 这里必须加锁
            lock (this)
            {
                if (++this.value > MASK_20_BIT - 1)
                {
                    this.value = 0;
                }

                v = this.value;
            }

            IDStruct idStruct = new(time, (uint)v);
            return idStruct.ToLong();
        }
    }
}